/**
 * 
 */
package it.uniroma3.dia.digraph.algorithm.kouterplanar.kouterplanar;

import it.uniroma3.dia.digraph.algorithm.utility.Utility;
import it.uniroma3.dia.digraph.algorithm.utility.stackedtri.StackedTriGraph;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.graphdrawing.graphml.xmlns.GraphType;
import org.graphdrawing.graphml.xmlns.NodeType;

/**
 * @author Cionzo
 *
 */
public class KouterplanarGraph extends StackedTriGraph{
    
    private GraphType graph;
    private Map<String, KouterplanarNode> kNodeMap;
    private Map<String, Set<String>> adjacencyMatrix;
    private Map<Integer, List<KouterplanarNode>> depth2nodes;
    
    /**
     * @param g
     */
    public KouterplanarGraph (GraphType g) {
	this.graph = g;	
	this.adjacencyMatrix = Utility.buildAdjacencyMatrix(this.graph);	
	this.initNodeMap();
	this.initNodes();
	this.initDepth2Nodes();
    }


    /**
     * 
     */
    private void initDepth2Nodes() {
	
	this.depth2nodes = new HashMap<Integer, List<KouterplanarNode>>();
	Map<Integer, List<NodeType>> d2n = Utility.decomposeToLayers(this.graph);
	List<KouterplanarNode> kDepth;
	List<NodeType> gDepth;
	
	for (Integer i : d2n.keySet()) {
	    gDepth = d2n.get(i);
	    kDepth = new LinkedList<KouterplanarNode>();
	    
	    for (NodeType node: gDepth) {
		kDepth.add(this.kNodeMap.get(node.getId()));
		this.kNodeMap.get(node.getId()).setDepth(i);
	    }
	    
	    this.depth2nodes.put(i, kDepth);
	}
    }


    /**
     * 
     */
    private void initNodeMap() {
	this.kNodeMap = new HashMap<String, KouterplanarNode>();
	List<NodeType> nodes = this.graph.getNodeCollection().getNode();
	
	for (NodeType node : nodes)
	    this.kNodeMap.put(node.getId(), new KouterplanarNode(node));
    }

    /**
     * 
     */
    private void initNodes() {
	List<KouterplanarNode> neighbors;
	Set<String> nids;
	
	for (KouterplanarNode current : this.kNodeMap.values()) {
	    neighbors = new LinkedList<KouterplanarNode>();
	    nids = this.adjacencyMatrix.get(current.getNode().getId());
	    
	    for (String nid : nids) 
		neighbors.add(this.kNodeMap.get(nid));
	    
	    current.setParentAndLambdas(neighbors, this.adjacencyMatrix);
	    
	}
	
    }

    /**
     * @return the graph
     */
    public GraphType getGraph() {
        return graph;
    }

    /**
     * @param graph the graph to set
     */
    public void setGraph(GraphType graph) {
        this.graph = graph;
    }

    /**
     * @return the kNodeMap
     */
    public Map<String, KouterplanarNode> getkNodeMap() {
        return kNodeMap;
    }

    /**
     * @param kNodeMap the kNodeMap to set
     */
    public void setkNodeMap(Map<String, KouterplanarNode> kNodeMap) {
        this.kNodeMap = kNodeMap;
    }

    /**
     * @return the adjacencyMatrix
     */
    public Map<String, Set<String>> getAdjacencyMatrix() {
        return adjacencyMatrix;
    }

    /**
     * @param adjacencyMatrix the adjacencyMatrix to set
     */
    public void setAdjacencyMatrix(Map<String, Set<String>> adjacencyMatrix) {
        this.adjacencyMatrix = adjacencyMatrix;
    }

    /**
     * @return the depth2nodes
     */
    public Map<Integer, List<KouterplanarNode>> getDepth2nodes() {
        return depth2nodes;
    }

    /**
     * @param depth2nodes the depth2nodes to set
     */
    public void setDepth2nodes(Map<Integer, List<KouterplanarNode>> depth2nodes) {
        this.depth2nodes = depth2nodes;
    }

    /* (non-Javadoc)
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode() {
	final int prime = 31;
	int result = 1;
	result = prime * result
		+ ((adjacencyMatrix == null) ? 0 : adjacencyMatrix.hashCode());
	return result;
    }

    /* (non-Javadoc)
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object obj) {
	if (this == obj)
	    return true;
	if (obj == null)
	    return false;
	if (getClass() != obj.getClass())
	    return false;
	KouterplanarGraph other = (KouterplanarGraph) obj;
	if (adjacencyMatrix == null) {
	    if (other.adjacencyMatrix != null)
		return false;
	} else if (!adjacencyMatrix.equals(other.adjacencyMatrix))
	    return false;
	return true;
    }

}
